<?php
namespace app\applet\controller;

use app\applet\model\Config as ConfigModel;
use app\applet\model\Applet as AppletModel;
use app\applet\model\AppletTpl as AppletTplModel;
use app\applet\model\AppletName as AppletNameModel;
use app\applet\model\Wechat as WechatModel;
use app\applet\model\Keyword as KeywordModel;
use app\applet\model\WechatBatchSend as WechatBatchSendModel;
use app\applet\model\Apply as ApplyModel;
use app\applet\model\User as UserModel;
use app\applet\model\UserDetail as UserDetailModel;
use app\applet\model\Setting as SettingModel;
use hema\wechat\WxBizMsgCrypt;
use hema\wechat\Driver;
use think\facade\Session;

/**
 * 第三方平台与微信通讯接口
 */

class Task extends \app\BaseController
{
    protected $wechat;    //公众号
    
    /**
     * 微信授权事件接收通知处理
     */
    public function wxopen()
    {
		// 接收公众号平台发送的消息
		$timeStamp = empty ( $_GET ['timestamp']) ? '' : trim ( $_GET ['timestamp'] );//时间戳
        $nonce = empty ( $_GET ['nonce'] ) ? '' : trim ( $_GET ['nonce'] );//随机数
        $msg_signature = empty ( $_GET['msg_signature'] ) ? '' : trim ( $_GET ['msg_signature'] );//签名
		$encrypt_type = empty ( $_GET['encrypt_type'] ) ? '' : trim ( $_GET ['encrypt_type'] );//加密类型，为 aes
        $encryptMsg = file_get_contents ('php://input' );
		$pc = new WxBizMsgCrypt();//创建解密类
		$msg = '';
		$errCode = $pc->decryptMsg($msg_signature, $timeStamp, $nonce, $encryptMsg, $msg);
		if($errCode == 0){
			$data = _xml_to_arr($msg);	//XML转换为数组
			//write_log($data, __DIR__);//用于测试callback.php接口
			//推送的ticket
			if($data['InfoType'] == 'component_verify_ticket'){
				//获取第三方配置信息
				$config = ConfigModel::detail();
				$config->component_verify_ticket = $data['ComponentVerifyTicket']; 
				//更新过期的令牌component_access_token
				if($config['expires_in'] < time()){
					//过期更新access_token
					$wx = new Driver;
					if($result = $wx->getComponentToken($data['ComponentVerifyTicket'])){
						$config->component_access_token = $result['component_access_token'];
						$config->expires_in = time()+3600;
					}
				}
				$config->save();	//保存ticket
				die('success');
			}
			//取消授权
			if($data['InfoType'] == 'unauthorized'){
				if($wechat = WechatModel::getWechat(['app_id' => $data['AuthorizerAppid']])){
					$wechat->save(['status' => 0]);
				}
				if($wxapp = AppletModel::getApplet(['app_id' => $data['AuthorizerAppid']])){
					$wxapp->save(['status' => 0]);
				}
				die('success');
			}
			//更新授权
			if($data['InfoType'] == 'updateauthorized'){
				
			}
			//成功授权
			if($data['InfoType'] == 'authorized'){
				
			}
			//小程序注册成功
			if($data['InfoType'] == 'notify_third_fasteregister'){
				$this->fasteregister($data);//验证状态
				die('success');				
			}
			die('success');
		}else{
			write_log('Callback 解密失败，code：'.$errCode, __DIR__);
		}
    }
	
	/**
     * 微信消息与事件接收通知处理
     */
    public function wechat(string $appid = '')
    {
    	$this->wechat = WechatModel::getWechat(['app_id' => $appid]);
		// 接收公众号平台发送的消息
		$nonce = empty ( $_GET ['nonce'] ) ?"" : trim ( $_GET ['nonce'] );
		$signature = empty ( $_GET['signature'] ) ? "" : trim ( $_GET ['signature'] );
		$timeStamp = empty ( $_GET ['timestamp']) ? "" : trim ( $_GET ['timestamp'] );
		$msg_signature = empty ( $_GET['msg_signature'] ) ? "" : trim ( $_GET ['msg_signature'] );
		$encryptMsg = file_get_contents ('php://input' );
		$pc = new WxBizMsgCrypt();//创建解密类
		$msg = '';		
		$errCode = $pc->decryptMsg($msg_signature, $timeStamp, $nonce, $encryptMsg, $msg);	
		if($errCode == 0){
			$data = _xml_to_arr($msg);	//XML转换为数组
			//write_log($data, __DIR__);
			//*********************************接收事件推送*****************************************
			if($data['MsgType']=='event'){
				//用户未关注时，进行关注后的事件推送
				if($data['Event']=='subscribe'){
					//是否设置了关注回复
					if($subscribe = SettingModel::getItem('subscribe',$this->wechat['applet_id'])){
						$this->replyMsg($subscribe,$data);//回复信息
					} 
					//获取粉丝资料
					$wx = new Driver;
					if($wechat_user = $wx->getWechatUserInfo($data['FromUserName'],$this->wechat['applet_id'])){
						//用户操作
						$model = new UserModel;
						$user_name = $model->subscribe($wechat_user,$this->wechat['applet_id']);
						if($this->wechat['applet_id'] == 0){
							$wx->sendServiceMsg([
								'type' => 'text',
								'content' => '请妥善保管您的账号和密码~
如忘记回复“找回账号”找回~
账号：' . $user_name . '
密码：123456'
							],$data['FromUserName'],$this->wechat['applet_id']);
						}
					}else{
						//返回文本提醒
						$wx->sendServiceMsg([
							'type' => 'text',
							'content' => $wx->getError()
						],$data['FromUserName'],$this->wechat['applet_id']);
					}
					die('success');
				}
				//用户已关注时扫码进入事件推送
				if($data['Event']=='SCAN'){
					die('success');
				}
				//取消关注事件
				if($data['Event']=='unsubscribe'){
					if($model = UserModel::getUser(['open_id' => $data['FromUserName']])){
						$model->unSubscribe();
					}
					die('success');
				}
				//扫描带参数二维码事件 - 用户未关注时，进行关注后的事件推送
				if($data['Event']=='subscribe' AND isset($data['EventKey'])){
					die('success');
				}
				//扫描带参数二维码事件 - 用户已关注时的事件推送
				if($data['Event']=='SCAN'){
					die('success');
				}
				//上报地理位置事件
				if($data['Event']=='LOCATION'){
					die('success');
				}
				//自定义菜单事件 - 点击菜单拉取消息时的事件推送
				if($data['Event']=='CLICK'){
					//判断是否来自公众号菜单并携带关键字
            		if(isset($data['EventKey']) AND !empty($data['EventKey'])){
            			$data['Content'] = $data['EventKey'];
            			$data['MsgType'] = 'text';
            			$this->textMsg($data);
            		}
					die('success');
				}
				//自定义菜单事件 - 点击菜单跳转链接时的事件推送
				if($data['Event']=='VIEW'){
					die('success');
				}
				//添加附近门店类目审核回调
				if($data['Event']=='nearby_category_audit_info'){
					//$this->nearby_category_audit_info($data);
					die('success');
				}
				//添加附近小程序地点审核回调
				if($data['Event']=='add_nearby_poi_audit_info'){
					write_log('添加附近小程序地点审核回调',__DIR__);
					die('success');
				}
				//群发任务回调事件推送
				if($data['Event']=='MASSSENDJOBFINISH'){
					$msg = WechatBatchSendModel::getSend(['msg_id' => $data['MsgID']]);
					$msg->backEdit($data);
					die('success');
				}
				//代码审核成功结果推送
				if($data['Event'] == 'weapp_audit_success'){
					//获取商户数据
					if($applet = AppletModel::getApplet(['user_name' => $data['ToUserName']])){ 
						if($tpl = AppletTplModel::getNew($applet['applet_id'])){
							//发布小程序模板
                            $wx = new Driver;
                            if($wx->release($applet['applet_id'])){
                                $tpl->save(['status' => 2]); //已上线
                                $applet->save(['applet_tpl_id' => $tpl['applet_tpl_id']]);
                            }else{
                            	$tpl->save(['status' => 3]);//待发布
                            }
						}
					}
					die('success');
				}
				//代码审核失败结果推送
                if($data['Event'] == 'weapp_audit_fail'){
                    //获取商户数据
					if($applet = AppletModel::getApplet(['user_name' => $data['ToUserName']])){ 
						if($tpl = AppletTplModel::getNew($applet['applet_id'])){
							$tpl->save(['status' => 1,'reason' => $data['Reason']]);//被拒绝
						}
					}
                    die('success');
                }
                //代码审核延后推送
                if($data['Event'] == 'weapp_audit_delay'){
                    //获取商户数据
					if($applet = AppletModel::getApplet(['user_name' => $data['ToUserName']])){ 
						if($tpl = AppletTplModel::getNew($applet['applet_id'])){
							$tpl->save(['status' => 4]);//审核延后
						}
					}
                    die('success');
                }
                //名称审核结果事件推送
                if($data['Event'] == 'wxa_nickname_audit'){
                    if($applet = AppletModel::getApplet([
						'user_name' => $data['ToUserName']
					])){ 
                        if($name = AppletNameModel::getAppletName(['nick_name' => $data['nickname'],'applet_id' => $applet['applet_id'],'status' => 0])){
                            //成功
                            if($data['ret']==3){
                                $name->save(['status' => 1]);
                                $applet->save(['app_name' => $data['nickname']]);
                            }
                            //失败
                            if($data['ret']==2){
                                $name->save(['status' => 2,'reason' => $data['reason']]);
                                $applet->save(['app_name' => $data['nickname'] . '->被拒绝：'.$data['reason']]);
                            }
                        }
                    }
                    die('success');
                }
			}
			//*********************************接收普通消息*****************************************
			//接收普通消息 - 文本消息
			if($data['MsgType']=='text'){
				$this->textMsg($data);//文本消息处理
				die('success');
			}
			//接收普通消息 - 图片消息
			if($data['MsgType']=='image'){
				//发什么回什么
				echo $this->msgTpl([
					'ToUserName' => $data['FromUserName'],
					'FromUserName' => $data['ToUserName'],
					'MsgType' => $data['MsgType'],
					'MediaId' => $data['MediaId']
				]);
				die('success');
			}
			//接收普通消息 - 语音消息
			if($data['MsgType']=='voice'){
				//发什么回什么
				echo $this->msgTpl([
					'ToUserName' => $data['FromUserName'],
					'FromUserName' => $data['ToUserName'],
					'MsgType' => $data['MsgType'],
					'MediaId' => $data['MediaId']
				]);
				die('success');
			}
			//接收普通消息 - 视频消息
			if($data['MsgType']=='video'){
				//发什么回什么
				echo $this->msgTpl([
					'ToUserName' => $data['FromUserName'],
					'FromUserName' => $data['ToUserName'],
					'MsgType' => 'text',
					'Content' => '我不看，太低俗~'
				]);
				die('success');
			}
			//接收普通消息 - 小视频消息
			if($data['MsgType']=='shortvideo'){
				die('success');
			}
			//接收普通消息 - 地理位置消息
			if($data['MsgType']=='location'){
				die('success');
			}
			//接收普通消息 - 链接消息
			if($data['MsgType']=='link'){
				die('success');
			}
			die('success');
		}else{
			write_log('Wechat 解密失败 - 错误代码：'.$errCode, __DIR__);
		}
    }
	
	/**
     * 处理文本消息
    */
	private function textMsg($data)
	{
		//是否设置了关键字回复
		switch($data['Content']){
			case 'id':
				echo $this->msgTpl([
						'ToUserName' => $data['FromUserName'],
						'FromUserName' => $data['ToUserName'],
						'MsgType' => 'text',
						'Content' => $data['FromUserName']
					]);
				break;
			case '找回账号':
				$this->getUserPassword($data);
				break;
			default:
				if($values = KeywordModel::getKeys($data['Content'],$this->wechat['applet_id'])){
					$this->replyMsg($values,$data);//回复信息
				}else{
					if($values = KeywordModel::getKeys('*',$this->wechat['applet_id'])){
						$this->replyMsg($values,$data);//回复信息
					}else{
						//没有，发什么回什么
						echo $this->msgTpl([
							'ToUserName' => $data['FromUserName'],
							'FromUserName' => $data['ToUserName'],
							'MsgType' => $data['MsgType'],
							'Content' => $data['Content']
						]);
					}
				}
		}
	}
	
	/**
     * 回复消息
    */
	private function replyMsg($msg,$data)
	{
		//是否开启
		if($msg['is_open']==1){
			//文字消息
			if($msg['type']=='text'){
				echo $this->msgTpl([
					'ToUserName' => $data['FromUserName'],
					'FromUserName' => $data['ToUserName'],
					'MsgType' => 'text',
					'Content' => $msg['content']['description']
				]);
			}			
			//图片消息
			if($msg['type']=='image'){
				echo $this->msgTpl([
				  'ToUserName' => $data['FromUserName'],
				  'FromUserName' => $data['ToUserName'],
				  'MsgType' => 'image',
				  'MediaId' => $msg['content']['media_id']
				]);
			}
			//语音消息
			if($msg['type']=='voice'){
				echo $this->msgTpl([
				  'ToUserName' => $data['FromUserName'],
				  'FromUserName' => $data['ToUserName'],
				  'MsgType' => 'voice',
				  'MediaId' => $msg['content']['media_id']
				]);
			}
			//视频消息
			if($msg['type']=='video'){
				echo $this->msgTpl([
				  'ToUserName' => $data['FromUserName'],
				  'FromUserName' => $data['ToUserName'],
				  'MsgType' => 'video',
				  'Title' => $msg['content']['title'],
				  'Description' => $msg['content']['description'],
				  'MediaId' => $msg['content']['media_id']
				]);	
			}
			//音乐消息
			if($msg['type']=='music'){
				echo $this->msgTpl([
				  'ToUserName' => $data['FromUserName'],
				  'FromUserName' => $data['ToUserName'],
				  'MsgType' => 'music',
				  'Title' => $msg['content']['title'],
				  'Description' => $msg['content']['description'],
				  'MusicUrl' => $msg['content']['url'],
				  'HQMusicUrl' => $msg['content']['hurl'],
				  'ThumbMediaId' => $msg['content']['media_id']
				]);
			}
			//图文消息
			if($msg['type']=='news'){
				echo $this->msgTpl([
				  'ToUserName' => $data['FromUserName'],
				  'FromUserName' => $data['ToUserName'],
				  'MsgType' => 'news',
				  'Articles' => [
				  	'title' => $msg['content']['title'],
				  	'description' => $msg['content']['description'],
				  	'picurl' => $msg['content']['picurl'],
				  	'url' => $msg['content']['url']
				  ]
				]);
			}
		}
	}
	
	/**
     * 将array转为xml
    */
	private function msgTpl($arr)
	{
		$xml ="<xml><ToUserName><![CDATA[" . $arr['ToUserName'] . "]]></ToUserName>";
		$xml .="<FromUserName><![CDATA[" . $arr['FromUserName'] . "]]></FromUserName>";
		$xml .="<CreateTime>" . time() . "</CreateTime>";
		$xml .="<MsgType><![CDATA[" . $arr['MsgType'] . "]]></MsgType>";
		switch($arr['MsgType']){
			case "text":
				$xml .="<Content><![CDATA[" . $arr['Content'] . "]]></Content>";
				break;
			case "image":
				$xml .= "<Image><MediaId><![CDATA[" . $arr['MediaId'] . "]]></MediaId></Image>";
				break;
			case "voice":
				$xml .= "<Voice><MediaId><![CDATA[" . $arr['MediaId'] . "]]></MediaId></Voice>";
				break;
			case "video":
				$xml .= "<Video><MediaId><![CDATA[" . $arr['MediaId'] . "]]></MediaId><Title><![CDATA[" . $arr['Title'] . "]]></Title><Description><![CDATA[" . $arr['Description'] . "]]></Description></Video>";
				break;
			case "music":
				$xml .= "<Music><Title><![CDATA[" . $arr['Title'] . "]]></Title><Description><![CDATA[" . $arr['Description'] . "]]></Description><MusicUrl><![CDATA[" . $arr['MusicUrl'] . "]]></MusicUrl><HQMusicUrl><![CDATA[" . $arr['HQMusicUrl'] . "]]></HQMusicUrl><ThumbMediaId><![CDATA[" . $arr['ThumbMediaId'] . "]]></ThumbMediaId></Music>";
				break;
			case "news":
				$xml .= "<ArticleCount>1</ArticleCount><Articles>";
				$xml .= "<item><Title><![CDATA[". $arr['Articles']['title'] ."]]></Title><Description><![CDATA[". $arr['Articles']['description'] ."]]></Description><PicUrl><![CDATA[". $arr['Articles']['picurl'] ."]]></PicUrl><Url><![CDATA[". $arr['Articles']['url'] ."]]></Url></item>";
				$xml .= "</Articles>";
				break;
		}
		$xml .= "</xml>";
		return $xml;
	}
	
	/**
	 * 找回用户密码
	 */
	private function getUserPassword($data)
	{
	    if($this->wechat['applet_id'] == 0){
			//获取用户信息ID
			if($model = UserModel::getUser(['open_id' => $data['FromUserName']])){
				if($model->retrieve()){
					echo $this->msgTpl([
						'ToUserName' => $data['FromUserName'],
						'FromUserName' => $data['ToUserName'],
						'MsgType' => 'text',
						'Content' => '恭喜：成功找回账号~
提醒：每次找回都要重置密码~
您的账号：' . $model['user_name'] . '
您的密码：123456'
                    ]);	
				}			
			}else{
				//返回文本提醒
				echo $this->msgTpl([
					'ToUserName' => $data['FromUserName'],
					'FromUserName' => $data['ToUserName'],
					'MsgType' => 'text',
					'Content' => '账号异常~
请取消关注该公众号后，在重新关注后进行操作。'
				]);
			}
		}
	}
	
	/**
     * 快速注册小程序状态验证
    */
	private function fasteregister(array $data)
	{
		//第一步、获取申请者资料
		$detail = UserDetailModel::getDetail([
			'merchant_name' => $data['info']['name'],
			'license_number' => $data['info']['code'],
			'legal_persona_wechat' => $data['info']['legal_persona_wechat'],
			'id_card_name' => $data['info']['legal_persona_name']
		]);
		//第二步、获取到了资料
		if($detail){
			//第三步、查询申请记录
			$apply = ApplyModel::where('apply_mode','<',30)->where([
				'user_id' => $detail['user_id'],
				'apply_status' => 20
			])->order('apply_id','desc')->find();
			//如果查询到了申请记录
			if($apply){
				//判断微信端审核状态
				if($data['status'] == 0){
					//审核成功 - 获取授权信息
					$wx = new Driver;
					if(!$auth = $wx->getAuth($data['auth_code'])){
					   return false; 
					}
					//获取授权应用的帐号基本信息
					if(!$result = $wx->getAppInfo($auth['authorizer_appid'])){
					    return false;
					}
					$app = $result['authorizer_info'];//得到授权应用的帐号基本信息
					$api_domain = '';
                    $signature = '';
                    //添加服务器域名
                    if($result = $wx->setServeDomain(0,'',$auth['authorizer_access_token'])){
                        $api_domain = $result['apiurl']; 
                    }
                    //设置小程序简介
                    if($result = $wx->setSignature(0,'',$auth['authorizer_access_token'])){
                        $signature = $result['signature'];
                    }
					$appletData = [
						'user_name' => $app['user_name'],					//原始ID
						'principal_name' => $app['principal_name'],			//主体名称
						'app_id' => $auth['authorizer_appid'],				//授权方APPid
						'access_token' => $auth['authorizer_access_token'],	//令牌
						'expires_in' => time()+7000,						//令牌过期时间
						'authorizer_refresh_token' => $auth['authorizer_refresh_token'],	//刷新令牌
						'status' => 1,	//是否授权
						'source' => 20 //注册来源
					];
					//判断是平台入驻还是小程序注册
					if(empty($apply['applet_id'])){
						//入驻
						$title = '商户入驻';
						$msg = '入驻成功';
						//新增小程序
						$appletData['app_type'] = 'food';
						$appletData['shop_mode'] = 10;//单门店
						$appletData['user_id'] = $apply['user_id'];
						$appletData['expire_time'] = strtotime('+1year');
						$model = new AppletModel;
						$apply->applet_id = $model->add($appletData,'apply');
					}else{
						//注册
						$title = '注册微信小程序';
						$msg = '注册成功';
						//更新小程序信息
						$model = AppletModel::getApplet(['applet_id' => $apply['applet_id']]); //获取商户数据
						$model->edit($appletData,'apply');
					}
					$apply->apply_status = 30;
				}else{
					//审核失败 (驳回操作)
					$status = [
						100001 => '已下发的模板消息法人并未确认且已超时（24h），未进行身份证校验',
						100002 => '已下发的模板消息法人并未确认且已超时（24h），未进行人脸识别校验',
						100003 => '已下发的模板消息法人并未确认且已超时（24h）',
						101 => '工商数据返回：“企业已注销”',
						102 => '工商数据返回：“企业不存在或企业信息未更新”',
						103 => '工商数据返回：“企业法定代表人姓名不一致”',
						104 => '工商数据返回：“企业法定代表人身份证号码不一致”',
						105 => '法定代表人身份证号码，工商数据未更新，请 5-15 个工作日之后尝试',
						1000 => '工商数据返回：“企业信息或法定代表人信息不一致”',
						1001 => '主体创建小程序数量达到上限',
						1002 => '主体违规命中黑名单',
						1003 => '管理员绑定账号数量达到上限',
						1004 => '管理员违规命中黑名单',
						1005 => '管理员手机绑定账号数量达到上限',
						1006 => '管理员手机号违规命中黑名单',
						1007 => '管理员身份证创建账号数量达到上限',
						1008 => '管理员身份证违规命中黑名单'
					];
					if($data['status'] == -1){
						$apply->reject = '企业与法人姓名不一致';
					}else{
						if(isset($status[$data['status']])){
							$apply->reject = $status[$data['status']];
						}else{
							$apply->reject = '未知原因';
						}
					}	
					$apply->apply_status = 40;
					//判断是平台入驻还是小程序注册
					if(empty($apply['applet_id'])){
						//入驻
						$title = '商户入驻 - 被驳回';
						$msg = '入驻失败';
					}else{
						//注册
						$title = '注册小程序 - 被驳回';
						$msg = '注册失败';
					}
				}
			}
			//发送微信通知
			sand_examine_msg($apply['apply_id'],$title,$msg,$apply['user_id']);
			$apply->save();
		}
		return true;
	}
}
